package tglinski.markdowneditor;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.util.Arrays;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

@SuppressWarnings("restriction")
public class MarkDownEditor {
	private HttpServer server;

	public static void main(String[] args) throws IOException {
		int port = 80;
		System.out.println("Program start args: " + Arrays.asList(args));

		for (String arg : args) {
			if (arg.startsWith("port=")) {
				try {
					port = Integer.parseInt(arg.replaceFirst("port=", ""));
				} catch (Exception e) {
					System.out.println("Invalid port");
				}
			}
		}

		MarkDownEditor server = new MarkDownEditor();
		server.start(port);
	}

	public void start(int port) throws IOException {
		System.out
				.println("Starting MarkDownEditor server using port: " + port);
		server = HttpServer.create(new InetSocketAddress(port), 0);
		server.createContext("/", new FileServingHandler());
		server.setExecutor(null); // creates a default executor
		server.start();
	}

	class FileServingHandler implements HttpHandler {
		private static final String ASSETS_FOLDER = "/assets/";
		private static final String MARKDOWN_FILE_EXTENSION = ".md";
		private static final String ASSETS_PREFIX = "MarkDownEditorMagicFolder/";
		private static final String STOP_URL = ASSETS_PREFIX + "stop";
		private static final String SAVE_URL = ASSETS_PREFIX + "save";
		private static final String USER_FILES = "";

		public void handle(HttpExchange t) throws IOException {

			String reqPath = t.getRequestURI().toString().replaceFirst("/", "");
			System.out.println("Handling request: " + reqPath);

			byte[] response;

			// static URL for stopping...
			if (reqPath.equals(STOP_URL)) {
				responseWith(t, "MARKDOWN EDITOR STOPPED".getBytes());
				server.stop(0);
				return;

				// ...and saving.
			} else if (reqPath.equals(SAVE_URL)) {
				response = "FILE SAVED".getBytes();
				String fileContent = convertStreamToString(t.getRequestBody());
				String filePath = USER_FILES
						+ t.getRequestHeaders().get("filePath").get(0)
								.replaceFirst("/", "");

				System.out.println("Saving " + fileContent.length()
						+ " chars to file: " + filePath);
				try {
					PrintWriter out = new PrintWriter(new File(filePath));
					out.print(fileContent);
					out.close();
				} catch (IOException e) {
					response = e.getMessage().getBytes();
				}
				System.out.println("Done");

				// Serve files from assets
			} else if (reqPath.startsWith(ASSETS_PREFIX)) {
				response = responseFromJarFile(reqPath.replace(ASSETS_PREFIX,
						ASSETS_FOLDER));

				// request for markdown file content
			} else if (reqPath.endsWith("?showSource")) {
				response = responseFromFile(USER_FILES
						+ reqPath.replace("?showSource", ""));

				// direct markdown files serve as editor for them
			} else if (reqPath.toLowerCase().endsWith(MARKDOWN_FILE_EXTENSION)) {
				response = responseFromJarFile(ASSETS_FOLDER + "editor.html");

				// serve directly all other files - probably images.
			} else {
				response = responseFromFile(USER_FILES
						+ t.getRequestURI().getPath());
			}

			responseWith(t, response);
		}

		private byte[] responseFromFile(String fileName) throws IOException {
			File f = new File(fileName);
			System.out.println("Loading file: " + f.getAbsolutePath()
					+ " (exists: " + f.exists() + ")");

			return f.exists() ? convertStreamToString(new FileInputStream(f))
					.getBytes() : null;
		}

		private byte[] responseFromJarFile(String fileName) throws IOException {

			InputStream input = getClass().getResourceAsStream(fileName);
			String content = convertStreamToString(input);
			System.out.println("Loading classpath file: " + fileName + ": "
					+ content == null ? "not found" : "OK");

			return content == null ? null : content.getBytes();
		}

		private void responseWith(HttpExchange t, byte[] response)
				throws IOException {

			int code = response == null ? 404 : 200;

			if (response == null) {
				response = ("NOT FOUND: " + USER_FILES + t.getRequestURI()
						.toString()).getBytes();
			}

			t.sendResponseHeaders(code, response.length);

			OutputStream os = t.getResponseBody();
			os.write(response);
			os.close();
		}

	}

	static String convertStreamToString(InputStream is) {
		@SuppressWarnings("resource")
		java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
		return s.hasNext() ? s.next() : "";
	}
}
